#include <list>
#include <string>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "CIpodLog.h"
#include "CIpodEvent.h"
#include "CIpodDevice.h"
#include "CIpodIap1.h"
#include "CIpodIap2.h"
#include "CIpodConfig.h"
#include "CIpodVehicle.h"
#include <sys/system_properties.h>

#ifdef __ANDROID__
struct hidraw_devinfo {
 __u32 bustype;
 __s16 vendor;
 __s16 product;
};
#else
#include <linux/hidraw.h>
#endif

#define IPOD_READ_TIMEOUT           2       // 数据读线程超时时间
#define HID_HEADER_LENGTH           2       // HID信息头长度
#define USB_PACKET_MAX_LENGTH       1024    // USB每包数据最大长度
//#define IPOD_HOST_HANDLE_PATH       "/dev/gadget_transfer"
#define IPOD_HOST_HANDLE_PATH       "/dev/zjinnova_iap"

static const uint8 iAP2CheckBuf[]       = { 0xFF, 0x55, 0x02, 0x00, 0xEE, 0x10 };
//55 02 00 ee 10
static const uint8 iAP2CheckBufHongQi[] = { 0x55, 0x02, 0x00, 0xEE, 0x10 };
static const uint8 iAP1ReqIdentifyBuf[] = { 0x55, 0x02, 0x00, 0x00, 0xFE };
static const uint8 iAP1AckBuf[]         = { 0x55, 0x04, 0x00, 0x02, 0x04, 0xEE, 0x08 };
static const uint8 iAP1NotSupportBuf[]  = { 0xFF, 0x55, 0x0E, 0x00, 0x13, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEB };

BtSendData          CIpodDevice::bt_send_data = NULL;
WiFiDataCallback    CIpodDevice::wifiDataCallback = NULL;

IpodPacket::IpodPacket() {
    clear();
}

IpodPacket::IpodPacket(const IpodPacket &packet) {
    exit = packet.exit;
    len = packet.len;
    memcpy(data, packet.data, sizeof(data));
    native = packet.native;
}

IpodPacket::~IpodPacket() {

}

void IpodPacket::clear() {
    exit = false;
    len = 0;
    memset(data, 0, sizeof(data));
    native = false;
    ignore = false;
}

CIpodDevice::CIpodDevice(const char *path) {
    if (path != NULL) {
        m_Path = path;
    }
	char	hid_once [ 20 ];
	__system_property_get("sys.xqcarplay.hid.once", hid_once);
	if(strlen(hid_once) > 0 )
	{
		m_hidOnce = atoi( hid_once );
	}
    m_Handle = 0;
    m_DeviceExist = false;
    m_ProcTid = 0;
    m_RecvTid = 0;
    m_NativeTid = 0;
    sem_init(&m_PacketSem, 0, 0);
    sem_init(&m_ProtocolSem, 0, 0);
    m_ProtInitState = IPODProtInitState::UNINIT;
    m_Iap2Support = false;
    pthread_mutex_init(&m_SendMutex, NULL);
    pthread_mutex_init(&m_PacketMutex, NULL);
    m_Protocol = NULL;
    m_Exiting = false;
}

CIpodDevice::~CIpodDevice()
{
    sem_destroy(&m_PacketSem);
    sem_destroy(&m_ProtocolSem);
    pthread_mutex_destroy(&m_SendMutex);
    pthread_mutex_destroy(&m_PacketMutex);
    CIpodLog::i("CIpodDevice::~CIpodDevice successfully.\n");
}

ipod_t CIpodDevice::getHandle() {
    return m_Handle;
}

int CIpodDevice::getConnMode() {
    return m_connMode;
}

std::string CIpodDevice::getPath() {
    return m_Path;
}
//                               0 1 2  3  4  5  6  7    8   9   10  11  12
static uint16 g_report_desc[] = {1,5,9, 13,17,25,49,95, 193,257,385,513,767,
		                           5,9, 13,17,25,49,95, 193,255
};

static uint16 findReportId(uint16 reportCount){
	uint16 len = 22;
	uint16 range = 0xFFFF;
	uint16 index = 1;
//	CIpodLog::i("CIpodDevice::send,findReportId  reportCount = %d \n",reportCount);
	for(int i=0;i<len;i++){
//		CIpodLog::i("CIpodDevice::send,findReportId id = %d , reportSize = %d \n",i, g_report_desc[i]);
		if(g_report_desc[i]>=reportCount){
			uint16 nextRange = g_report_desc[i] - reportCount;
			if( nextRange < range){
				range = nextRange;
				index = i;
			}
		}
	}
//	CIpodLog::i("CIpodDevice::send,decided use ReportId = %d , reportSize = %d \n",index ,g_report_desc[index]);
	return index;
}

int CIpodDevice::send(const uint8 *data, uint16 len, bool native) {
    int ret = -1;
	int retryCount =0 ;

    if (m_Exiting) return -1;

    if (native) {// eap send data
         CIpodLog::i("CIpodDevice::send,EAP Send Data !\n");
        if ((ret = write(CIpodNative::getHandle(), data, len)) < 0) {
            CIpodLog::e("CIpodDevice::send, write native error!\n");
        } else {
            ret = 0;
        }
    }
    else if ( m_connMode == ConnMode_BLUETOOTH){ //buletooth send data
        if(bt_send_data != NULL){
            bt_send_data(len,data);
        }else{
            CIpodLog::e("CIpodDevice::send, bt_send_data is null!\n");
        }
        ret = 0;
    }
    else if( m_connMode == ConnMode_WiFi )
    {
        if(wifiDataCallback != NULL){
        	CIpodLog::w("[IAP2-wifi]-Send %d bytes: \n",len);
        	this->debugHexBuf("[IAP2-wifi]-Send", data, len); //Tinker
//        	debugHexBuf("iAP2MessageWrite", data,len);  //屏蔽打印数据
            wifiDataCallback(len,data);
        }else{
            CIpodLog::e("CIpodDevice::send, wifiDataCallback is null!\n");
        }
        ret = 0;
    }
    else { //iap2 send data
        if (CIpodConfig::getMode() == Mode_MEDIA || CIpodConfig::getHidg() == 1 ) {
            if (m_Handle <= 0) return -1;
            pthread_mutex_lock(&m_SendMutex);
            reSendData :uint16 validDataLen = USB_PACKET_MAX_LENGTH - HID_HEADER_LENGTH;
            uint16 count = len / validDataLen + ((len % validDataLen) == 0 ? 0 : 1);
            uint8 buf[USB_PACKET_MAX_LENGTH];
            if (count == 1) {
                buf[0] = 0x01;
                uint16 totalLen = len + 1;
                uint16 reportId = findReportId(totalLen);
                uint16 reportLen = g_report_desc[reportId];

                reportLen += 1;
            	uint8* newBuf = (uint8*)malloc(reportLen);
            	memset(newBuf,0,reportLen);
            	newBuf[0] = reportId;
            	newBuf[1] = 0x00;
                memcpy(newBuf + HID_HEADER_LENGTH, data, len);

//                CIpodLog::w("hidg-iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                std::string details = debugHexBufString(data, len);
//                CIpodLog::w("hidg-iAP2LinkPackets:: | Sent      | Apple device | ACK  |  %d | %d | %s\n",data[5], data[6], details.data());
//                debugHexBuf("hidg-IAP2-USB-Send", newBuf,reportLen);  //屏蔽打印数据

                uint16 PACKET_LEN = 64;
                if(m_hidOnce == 1 )
                {
                	PACKET_LEN = 4000;
                }
                if(reportLen > PACKET_LEN ){
                	uint16 total   = reportLen / PACKET_LEN;
                	uint16 balance = reportLen % PACKET_LEN;
                	uint16 startIndex = 0;
                    if (balance == 0) {
                        // 可以整除
                        for (int j = 0; j < total; j++) {
                            uint8* frame = (uint8*)malloc(PACKET_LEN);
                            memset(frame, 0, PACKET_LEN );
                            memcpy(frame, newBuf+startIndex, PACKET_LEN);
                            startIndex += PACKET_LEN;
                            ret = write(m_Handle, frame, PACKET_LEN);
                            free(frame);
                        }
                    } else {
                        // 不能被整除
                        total = total + 1;
                        for (int j = 0; j < total; j++) {
                            if (j != total - 1) {
                            	uint8* frame = (uint8*)malloc(PACKET_LEN);
                                memset(frame, 0, PACKET_LEN );
                                memcpy(frame, newBuf+startIndex, PACKET_LEN);
                                startIndex += PACKET_LEN;
                                ret = write(m_Handle, frame, PACKET_LEN);
                                free(frame);
                            } else {
                            	uint8* frame = (uint8*)malloc(balance);
                                memset(frame, 0, balance );
                                memcpy(frame, newBuf+startIndex, balance);
                                startIndex += balance;
                                ret = write(m_Handle, frame, balance);
                                free(frame);
                            }
                        }
                    }

                }else{
                	ret = write(m_Handle, newBuf, reportLen);
                }
                free(newBuf);
            } else {
                uint16 alreadyWriteLen = 0;
                for (uint16 i = 0; i < count; i++) {
                    buf[0] = 0x01;
                    if (i == 0) {
                        buf[1] = 0x02;
                    } else if (i == count -1) {
                        buf[1] = 0x01;
                    } else {
                        buf[1] = 0x03;
                    }
                    if (i == count - 1) {
                        uint16 totalLen = len - validDataLen * (count - 1) + HID_HEADER_LENGTH;
                        uint16 reportId = findReportId(totalLen);
                        buf[0] = reportId;
                        memcpy(buf + HID_HEADER_LENGTH, data + alreadyWriteLen, len - validDataLen * (count - 1));
                        if(g_report_desc[reportId]!=totalLen){
                        	uint8* newBuf = (uint8*)malloc(g_report_desc[reportId]);
                        	memset(newBuf,0,g_report_desc[reportId]);
                        	memcpy(newBuf,buf,totalLen);

//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                            std::string details1 = debugHexBufString(data, len);
//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Sent      | Apple device | ACK  |  %d | %d | %s\n",data[5], data[6], details1.data());

//                            debugHexBuf("hidg-IAP2-USB-Send", newBuf, g_report_desc[reportId]); //屏蔽打印数据
                            ret = write(m_Handle, newBuf, g_report_desc[reportId]);
                            free(newBuf);
                            alreadyWriteLen += (len - validDataLen * (count - 1));
                        }else{
//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                            std::string details2 = debugHexBufString(data, len);
//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Sent      | Apple device | ACK  |  %d | %d | %s\n",data[5], data[6], details2.data());
//                            debugHexBuf("hidg-IAP2-USB-Send", buf, totalLen); //屏蔽打印数据
                            ret = write(m_Handle, buf, len - validDataLen * (count - 1) + HID_HEADER_LENGTH);
                            alreadyWriteLen += (len - validDataLen * (count - 1));
                        }
                    } else {
                        uint16 totalLen = USB_PACKET_MAX_LENGTH;
                        uint16 reportId = findReportId(totalLen);
                        buf[0] = reportId;

                        memcpy(buf + HID_HEADER_LENGTH, data + alreadyWriteLen, validDataLen);
                        if(g_report_desc[reportId]!=totalLen){
                        	uint8* newBuf = (uint8*)malloc(g_report_desc[reportId]);
                        	memset(newBuf,0,g_report_desc[reportId]);
                        	memcpy(newBuf,buf,totalLen);

//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                            std::string details3 = debugHexBufString(data, len);
//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Sent      | Apple device | ACK  |  %d | %d | %s\n",data[5], data[6], details3.data());

//                            debugHexBuf("hidg-IAP2-USB-Send", newBuf, g_report_desc[reportId]); //屏蔽打印数据
                            ret = write(m_Handle, newBuf, g_report_desc[reportId]);
                            free(newBuf);
                            alreadyWriteLen += validDataLen;
                        }else{
//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                            std::string details4 = debugHexBufString(data, len);
//                            CIpodLog::w("hidg-iAP2LinkPackets:: | Sent      | Apple device | ACK  |  %d | %d | %s\n",data[5], data[6], details4.data());

//                            debugHexBuf("hidg-IAP2-USB-Send", buf, totalLen); //屏蔽打印数据
                            ret = write(m_Handle, buf, USB_PACKET_MAX_LENGTH);
                            alreadyWriteLen += validDataLen;
                        }
                    }
                }
            }
            if (ret < 0) {
                CIpodLog::w("CIpodDevice::send, send error in device mode (%d)--%s\n", errno, strerror(errno));
                usleep(200000);
				retryCount ++;
                CIpodLog::e("CIpodDevice::send failed, retryCount:%d m_DeviceExist:%d m_Exiting:%d!\n",retryCount,m_DeviceExist,m_Exiting);
                if(retryCount <3 && m_DeviceExist)
				{
					CIpodLog::w("CIpodDevice::send, send error in device mode (%d)--%s --- retryCount:(%d)\n", errno, strerror(errno), retryCount);
					goto reSendData;
				}
//                CIpodEvent::sendEvent(IPOD_EVT_CONNECT_STATUS_CHANGED, m_Handle, 0);
                ret = -1;
            } else {
//                debugHexBuf("write", data, len);
                ret = 0;
            }
            pthread_mutex_unlock(&m_SendMutex);
        }else if (CIpodConfig::getMode() == Mode_CARLIFE
                || CIpodConfig::getMode() == Mode_CARPLAY) {
        	//Tinker
            if (m_Handle <= 0) return -1;
            pthread_mutex_lock(&m_SendMutex);
//            CIpodLog::w("iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//            std::string details = debugHexBufString(data, len);
//            CIpodLog::w("iAP2LinkPackets:: | Sent      | Apple device | ACK  |  %d | %d | %s\n",data[5], data[6], details.data());
            CIpodLog::w("[IAP2-libusb]-Send %d bytes: \n",len);
            debugHexBuf("[IAP2-libusb]-Send", data, len); //发送数据
            //此处需要将数据通过配件传
            int actual=0;
            uint8 data_out[len];
            memcpy(data_out,data,len);
            ret = CIpodEvent::write(m_Handle, data_out,len,&actual);
//            ret = write(m_Handle, data, len); //modify for reverse carplay Tinker
            if (ret < 0) {
                CIpodLog::w("write gadget_transfer error. errno: %d, errorstr: %s\n", errno, strerror( errno ) );
                ret = 0;
            } else {
                ret = 0;
            }
            pthread_mutex_unlock(&m_SendMutex);
        }
    }
    return ret;
}

bool CIpodDevice::isDeviceExist() {
    return m_DeviceExist;
}

bool CIpodDevice::isExiting() {
    return m_Exiting;
}

int CIpodDevice::create()
{
	CIpodLog::i("[ SharkCarPlay ] step 1: create iAP device and iAP2 support: %d.\n", m_Iap2Support);
	CIpodLog::i("create iAP device and iAP2 support: %d.\n", m_Iap2Support);
    int ret = -1;
    if ((ret = openDevice()) == -1) {
        CIpodLog::e("CIpodDevice::create, device open failed!\n");
        return ret;
    }
    if (CIpodConfig::getIdentification()->eaprotocol.nativeid > 0 && CIpodConfig::getMode() == Mode_CARLIFE)
    {
        if ((ret = CIpodNative::init()) != 0) {
            CIpodLog::e("CIpodDevice::create, native device open failed!\n");
            return ret;
        } else {
            if ((ret = pthread_create(&m_NativeTid, NULL, nativeThread, (void *)this)) != 0) {
                CIpodLog::e("CIpodDevice::create, native thread create failed!\n");
                return ret;
            }
            CIpodNative::registerSigioHandle();
        }
    }
    if ((ret = pthread_create(&m_ProcTid, NULL, procThread, (void *)this)) != 0) {
        CIpodLog::e("CIpodDevice::create, proc thread create failed!\n");
        return ret;
    }else{
    	m_ProcTidPtr = &m_ProcTid;
    	CIpodLog::d("CIpodDevice::create, proc thread create succeed!\n");
    }
    if(m_connMode == IPOD_CONN_TYPE_USB_HOST || m_connMode == IPOD_CONN_TYPE_USB_DEVICE || m_connMode == IPOD_CONN_TYPE_HIDG){
        if ((ret = pthread_create(&m_RecvTid, NULL, recvThread, (void *)this)) != 0) {
            CIpodLog::e("CIpodDevice::create, recv thread create failed!\n");
            return ret;
        }else{
        	m_RecvTidPtr = &m_RecvTid;
        	CIpodLog::d("CIpodDevice::create, recv thread create succeed!\n");
        }
    }
    m_DeviceExist = true;

    return 0;
}

int CIpodDevice::connectIap2() {
	CIpodLog::i("[  Device   ] step 1: iAP2 Link Initialization start and iAP2 support: %d.\n", m_Iap2Support);
    CIpodLog::i("iAP2 Link Initialization start.\n");
    int ret = -1;

    if (CIpodConfig::getProtocol() == IPODProtocol::IAP1) {
        m_Protocol = new CIpodIap1();
        m_ProtInitState = IPODProtInitState::SUCCEED;
    } else {
            if (checkIap2Support() != -1) {
            if (m_Iap2Support)
            {
                CIpodLog::i("iAP2 Link CheckIap2Support success.\n");
                m_Protocol = new CIpodIap2();
            }
            else
            {
                CIpodLog::e("iAP2 Link Initialization Detect, but not support iAP2.\n");
                if (CIpodConfig::getProtocol() == IPODProtocol::IAP2)
                {
                    send(iAP1NotSupportBuf, sizeof(iAP1NotSupportBuf));
                } else if (CIpodConfig::getProtocol() == IPODProtocol::ALL) {
                    m_Protocol = new CIpodIap1();
                }
            }
        }
    }
    if (m_Protocol != NULL) {
        CIpodLog::i("iAP2 Link m_Protocol != NULL. \n");
        m_Protocol->registerProxy(this);
        ret = m_Protocol->init(m_connMode);
        CIpodLog::i("iAP2 Link m_Protocol != NULL end. \n");
    } else {
        CIpodLog::e("CIpodDevice::create, ipod protocol is null!\n");
        ret = -1;
    }

    if (ret == 0) {
        CIpodEvent::sendEvent(IPOD_EVT_CONNECT_STATUS_CHANGED, m_Handle, 1);
//		if (m_Protocol != NULL) {
//			m_Protocol->getDeviceInformation();
//		}
    }
    CIpodLog::i("CIpodDevice::connectIap2 result = %d . \n",ret);
    return ret;
}

int CIpodDevice::destroy() {
    CIpodLog::i("CIpodDevice::destroy start handle: %d\n", m_Handle);

    int ret = -1;
    if(m_connMode == ConnMode_USB_HOST || m_connMode == ConnMode_USB_DEVICE || m_connMode == ConnMode_Hidg)
    {
        if (m_Protocol != NULL) {
            ret = m_Protocol->deinit();
        }
    }
    m_Exiting = true;

    if (m_Handle > 0) {
        close(m_Handle);
        m_Handle = 0;
    }
    CIpodLog::i("CIpodDevice::destroy exit handle successfully.\n");

    if(m_connMode == ConnMode_BLUETOOTH){
        CIpodVehicle::setbtSppConnStatus(ipod_SppState_ReadyNoInitialized);
    }else{
        CIpodVehicle::setWiFiConnStatus(WIFI_NOCONNECT);
    }

    if (m_ProcTidPtr) {
//        IpodPacket *packet = new IpodPacket();
//        if (NULL != packet) {
//            packet->exit = true;
//            packetAdd(packet);
//            delete packet;
//        }
        sem_post(&m_PacketSem);
        if (m_ProcTidPtr)
        {
        	pthread_join(m_ProcTid, NULL);
        	m_ProcTid = 0;
        	m_ProcTidPtr = NULL;
        }


//        usleep(2000);
//        CIpodLog::i("CIpodDevice::destroy, exit pthread_join m_ProcTid \n");
//        if(m_Packets.empty()){
//            CIpodLog::i("CIpodDevice::destroy, m_Packets is empty ...\n");
//        } else {
//            for (std::list<IpodPacket *>::iterator iter = m_Packets.begin(); iter != m_Packets.end(); ++iter) {
//                IpodPacket *packet = *iter;
//                if (NULL != packet) {
//                    delete packet;
//                }
//                iter = m_Packets.erase(iter);
//                //++iter;
//            }
//            if(m_Packets.empty()){
//                CIpodLog::i("CIpodDevice::destroy, erase m_Packets is empty ...\n");
//            }
//		}
    }
    CIpodLog::i("iAP2 ProcessThread has already terminated.\n");

//    if (m_RecvTid > 0) {
//        pthread_join(m_RecvTid, NULL);
//        m_RecvTid = 0;
//    }
    CIpodLog::i("iAP2 ProcessThread has already terminated.m_RecvTidPtr = %p \n",m_RecvTidPtr);
    if ( m_RecvTidPtr ) {
    	 CIpodLog::i("iAP2 ProcessThread has already terminated wait. \n");
        pthread_join(m_RecvTid, NULL);
        m_RecvTid = 0;
        m_RecvTidPtr = NULL;
        usleep(1200);
    }
    CIpodLog::i("iAP2 ReceiveThread has already terminated.\n");

    if (m_NativeTid > 0) {
        pthread_join(m_NativeTid, NULL);
        m_NativeTid = 0;
    }
    CIpodLog::i("iAP2 NativeThread has already terminated.\n");


    if (m_Protocol != NULL) {
        // ret = m_Protocol->deinit();
        m_Protocol->unregisterProxy();
        delete m_Protocol;
        m_Protocol = NULL;
    }

    CIpodLog::i("CIpodDevice::destroy successfully.\n");
    return ret;
}

int CIpodDevice::notifyBtStatus(bool connected) {
    if (m_Protocol != NULL) {
        return m_Protocol->notifyBtStatus(connected);
    }
    return -1;
}

int CIpodDevice::notifyUSBAudioStatus(bool enabled) {
    if (m_Protocol != NULL) {
        return m_Protocol->notifyUSBAudioStatus(enabled);
    }
    return -1;
}

int CIpodDevice::sendMediaCommand(int command) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendMediaCommand(command);
    }
    return -1;
}

int CIpodDevice::sendMediaCommandDown(int command) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendMediaCommandDown(command);
    }
    return -1;
}

int CIpodDevice::sendMediaCommandUp(int command) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendMediaCommandUp(command);
    }
    return -1;
}

int CIpodDevice::sendMediaCommandLibraryInfo(void *mediaInfo) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendMediaCommandLibraryInfo(mediaInfo);
    }
    return -1;
}

int CIpodDevice::sendStartLocationInformation(int start) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendStartLocationInformation(start);
    }
    return -1;
}

int CIpodDevice::sendStartDeviceTimeUpdate() {
    if (m_Protocol != NULL) {
        return m_Protocol->sendStartDeviceTimeUpdate();
    }
    return -1;
}

int CIpodDevice::sendCallStateUpdateInfo(void *callStateInfo) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendCallStateUpdateInfo(callStateInfo);
    }
    return -1;
}

int CIpodDevice::setPlayingTrackPosition(uint32 position) {
    if (m_Protocol != NULL) {
        return m_Protocol->setPlayingTrackPosition(position);
    }
    return -1;
}

int CIpodDevice::getShuffleMode(int *mode) {
    if (m_Protocol != NULL) {
        return m_Protocol->getShuffleMode(mode);
    }
    return -1;
}

int CIpodDevice::getRepeatMode(int *mode) {
    if (m_Protocol != NULL) {
        return m_Protocol->getRepeatMode(mode);
    }
    return -1;
}

int CIpodDevice::getPlayingTrackDuration(int * duration)
{
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingTrackDuration(duration);
    }
    return -1;
}

int CIpodDevice::getPlayingTrackTitle(std::string &title) {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingTrackTitle(title);
    }
    return -1;
}

int CIpodDevice::getPlayingTrackAlbum(std::string &album) {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingTrackAlbum(album);
    }
    return -1;
}

int CIpodDevice::getPlayingTrackArtist(std::string &artist) {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingTrackArtist(artist);
    }
    return -1;
}

int CIpodDevice::getPlayingTrackAlbumArtwork() {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingTrackAlbumArtwork();
    }
    return -1;
}

int CIpodDevice::getPlayStatus(IPODPlayStatus *status) {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayStatus(status);
    }
    return -1;
}

int CIpodDevice::getPlayingTrackInfo(int32 *index, uint32 *count) {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingTrackInfo(index, count);
    }
    return -1;
}

int CIpodDevice::getPlayingChapterInfo(int32 *index, uint32 *count) {
    if (m_Protocol != NULL) {
        return m_Protocol->getPlayingChapterInfo(index, count);
    }
    return -1;
}

int CIpodDevice::isListLevelSupported(bool *supported) {
    if (m_Protocol != NULL) {
        return m_Protocol->isListLevelSupported(supported);
    }
    return -1;
}

int CIpodDevice::resetMusicList(uint32 *num) {
    if (m_Protocol != NULL) {
        return m_Protocol->resetMusicList(num);
    }
    return -1;
}

int CIpodDevice::selectMusicList(int32 index, int32 level, uint32 *num) {
    if (m_Protocol != NULL) {
        return m_Protocol->selectMusicList(index, level, num);
    }
    return -1;
}

int CIpodDevice::getMusicList(uint32 startIndex, uint32 readCount, IPODMusicList *musicList) {
    if (m_Protocol != NULL) {
        return m_Protocol->getMusicList(startIndex, readCount, musicList);
    }
    return -1;
}

int CIpodDevice::getMusicList_c(uint32 startIndex, uint32 readCount, C_IPODMusicList *musicList) {
    if (m_Protocol != NULL) {
        return m_Protocol->getMusicList_c(startIndex, readCount, musicList);
    }
    return -1;
}

int CIpodDevice::selectMusicPlayingList(int32 index) {
    if (m_Protocol != NULL) {
        return m_Protocol->selectMusicPlayingList(index);
    }
    return -1;
}

int CIpodDevice::getMusicPlayingList(uint32 startIndex, uint32 readCount, C_IPODMusicList *musicList) {
    if (m_Protocol != NULL) {
        return m_Protocol->getMusicPlayingList(startIndex, readCount, musicList);
    }
    return -1;
}

int CIpodDevice::launchApp(const char *appBundleID) {
    if (m_Protocol != NULL) {
        return m_Protocol->launchApp(appBundleID);
    }
    return -1;
}

int CIpodDevice::setLocationInformation(const char *sentence)
{
    if (m_Protocol != NULL) {
        return m_Protocol->setLocationInformation(sentence);
    }
    return -1;
}

int CIpodDevice::iap2CarPlayStartSession(int type){
    if (m_Protocol != NULL) {
        return m_Protocol->carPlayStartSession(type);
    }
    return -1;
}

int CIpodDevice::ipod_BT_spp_data_pro(int cDataLen, const char * pData)
{
    if(m_Exiting)return 0;

    if(!m_Iap2Support)
    {
        if (memcmp(iAP2CheckBuf, pData, sizeof(iAP2CheckBuf)) == 0)
        {
            CIpodLog::i("[  Device   ] step 2:  DETECT over Rfcomm.\n");
            m_ProtInitState = IPODProtInitState::SUCCEED;
            m_Iap2Support = true;
            sem_post(&m_ProtocolSem);
            return 0;
        }
    }

    uint16 length1 = IAP2_BIG_ENDIAN( pData[2], pData[3] );
    uint16 length2 = 0;
    uint16 length3 = 0;

    // CIpodLog::w( "Rfcomm data ( Device -> Accessory ) size: %d. First iAP2 Packet size: %d.\n", cDataLen, length1 );

    // only one iAP2 Packet in Rfcomm data, analyse first iAP2 Packet.

    IpodPacket *packet = new IpodPacket();

    packet->len = length1;
    packet->native = false;
    memcpy(packet->data, pData, length1);
    packetAdd(packet);

    // more than one iAP2 Packet in Rfcomm data, just anlayse second iAP2 Packet( ugly ).

    if( cDataLen > length1 )
    {
        length2 = IAP2_BIG_ENDIAN( pData[length1 + 2], pData[length1 + 3] );

        CIpodLog::w( "Rfcomm data ( Device -> Accessory ) size: %d, First iAP2 Packet size: %d, Second iAP2 Packet size: %d\n", cDataLen, length1, length2 );

        IpodPacket *packet = new IpodPacket();

        packet->len = length2;
        packet->native = false;
        memcpy(packet->data, pData + length1, length2);
        packetAdd(packet);
    }

    // the third iAP2 Packet

    if( cDataLen > length1 + length2 )
    {
        length3 = IAP2_BIG_ENDIAN( pData[ length1 + length2 + 2 ], pData[ length1 + length2 + 3 ] );

        CIpodLog::w( "Rfcomm data ( Device -> Accessory ) size: %d, First iAP2 Packet size: %d, Second iAP2 Packet size: %d, Third iAP2 Packet size: %d\n",
            cDataLen, length1, length2, length3 );

        IpodPacket *packet = new IpodPacket();

        packet->len = length3;
        packet->native = false;
        memcpy(packet->data, pData + length1 + length2, length3);
        packetAdd(packet);
    }

    return 0;
}

int CIpodDevice::sendWiFiData( int cDataLen, const char * pData )
{
    if(m_Exiting)return 0;

	CIpodLog::w("[IAP2-wifi]-Recv %d bytes: \n",cDataLen);
	this->debugHexBuf("[IAP2-wifi]-Recv", (const uint8 *)pData, cDataLen); //Tinker

//    if( !m_Iap2Support )
    {
        if (memcmp(iAP2CheckBuf, pData, sizeof(iAP2CheckBuf)) == 0)
        {
            CIpodLog::i("[  Device   ] step 2: BMW DETECT over Wi-Fi.\n");
            m_ProtInitState = IPODProtInitState::SUCCEED;
            m_Iap2Support = true;
            sem_post(&m_ProtocolSem);
            //需要回复一条给车机 Tinker
            if (this->send(iAP2CheckBuf, sizeof(iAP2CheckBuf)) == -1) {
                CIpodLog::i("CIpodDevice::wifi responseIap2Support, send error! %s\n", strerror(errno));
            }else{
            	CIpodLog::i("CIpodDevice::wifi responseIap2Support, send success!\n");
            }
            return 0;
        }
    }
    IpodPacket *packet = new IpodPacket();

    packet->len = cDataLen;
    packet->native = false;
    memcpy(packet->data, pData, cDataLen);
    packetAdd(packet);

    return 0;
}

void CIpodDevice::ipodRegistBtSppSendData(BtSendData n_bt_spp_send_data){
    if(n_bt_spp_send_data != NULL){
        CIpodDevice::bt_send_data = n_bt_spp_send_data;
    }
}

void CIpodDevice::setWiFiDataCallback( WiFiDataCallback callback )
{
    if( callback != NULL )  CIpodDevice::wifiDataCallback = callback;
}

int CIpodDevice::iap2BluetoothPairingAccessoryInformation(const char * inPairingDataP192,const char * inPairingDataP256){
    if (m_Protocol != NULL) {
        return m_Protocol->bluetoothPairingAccessoryInformation(inPairingDataP192,inPairingDataP256);
    }
    return -1;
}

int CIpodDevice::iap2BluetoothPairingStatus( int success, const char * cancelReason){
    if (m_Protocol != NULL) {
        return m_Protocol->bluetoothPairingStatus(success,cancelReason);
    }
    return -1;
}

int CIpodDevice::iap2OOBBTPairingCompletionInformation(int resultCode ){
    if (m_Protocol != NULL) {
        return m_Protocol->oOBBTPairingCompletionInformation(resultCode);
    }
    return -1;
}

int CIpodDevice::sendEAData(const uint8 *data, uint16 len) {
    if (m_Protocol != NULL) {
        return m_Protocol->sendEAData(data, len);
    }
    return -1;
}

int CIpodDevice::getEANativeState() {
    return CIpodNative::getNativeState();
}

int CIpodDevice::openDevice() {
	CIpodLog::i("CIpodDevice::openDevice mode= %d ,ConnMode=%d ",CIpodConfig::getMode(),CIpodConfig::connMode());
    int ret = -1;
    int handle = 0;
    if ((CIpodConfig::getMode() == Mode_MEDIA) ||
        (CIpodConfig::getMode() == Mode_CARPLAY && CIpodConfig::connMode() == ConnMode_USB_DEVICE)) {
        m_connMode = ConnMode_USB_DEVICE;
        std::list<std::string> devices;
		bool isEmpty = m_Path.empty();
		CIpodLog::i("CIpodDevice::openDevice --- isEmpty == %d", isEmpty);
        if (isEmpty) {
            int num = 0;
            FILE *fstream = NULL;
            char buff[1024] = { 0 };
            if (NULL == (fstream = popen("ls /dev/hidraw* |grep -c 'hidraw'", "r"))) {
                CIpodLog::e("CIpodDevice::openDevice, execute command failed: %s", strerror(errno));
                return -1;
            }
            if (NULL == fgets(buff, sizeof(buff), fstream)) {
                CIpodLog::e("CIpodDevice::openDevice, execute command buf is null\n");
                pclose(fstream);
                return -1;
            }
            pclose(fstream);
            if (buff[0] <= '9' && buff[0] >= '0') {
                num = buff[0] - '0';
            }
            for (int i = 0; i < num; i++) {
                char str[128] = { 0 };
                sprintf(str, "/dev/hidraw%d", i);
                devices.push_back(str);
            }
        } else {
            devices.push_back(m_Path);
        }

        for (std::list<std::string>::iterator iter = devices.begin(); iter != devices.end(); ++iter) {
            if ((handle = open(iter->data(), O_RDWR)) > 0) {
                if (isIpodDevice(handle)) {
                    ret = 0;
                    break;
                } else {
                    close(handle);
                }
            }
        }
    }
    else if ((CIpodConfig::getMode() == Mode_CARLIFE) || (CIpodConfig::getMode() == Mode_CARPLAY && CIpodConfig::connMode() == ConnMode_Hidg))
    {
//        if ((handle = open(IPOD_HOST_HANDLE_PATH, O_RDWR)) > 0) {
        if ((handle = open("/dev/hidg0", O_RDWR)) > 0) {
            CIpodLog::i("open iAP2 over Hidg device success.\n");
            m_connMode = ConnMode_Hidg;
            ret = 0;
        } else {
            CIpodLog::i("ipod usb Hidg device open failed!\n");
            ret = -1;
        }
    }
    else if ((CIpodConfig::getMode() == Mode_CARLIFE) || (CIpodConfig::getMode() == Mode_CARPLAY && CIpodConfig::connMode() == ConnMode_USB_HOST))
    {
//        if ((handle = open(IPOD_HOST_HANDLE_PATH, O_RDWR)) > 0) {
        if ((handle = open("/dev/hidg0", O_RDWR)) > 0) {
            CIpodLog::i("open iAP2 over HostUsb device success.\n");
            m_connMode = ConnMode_USB_HOST;
            ret = 0;
        } else {
            CIpodLog::i("ipod usb host device open failed!\n");
            handle = 1008;
            m_connMode = ConnMode_USB_HOST;
            ret = 0;
        }
    }
    else if (CIpodConfig::getMode() == Mode_CARPLAY && CIpodConfig::connMode() == ConnMode_BLUETOOTH)
    {
        CIpodLog::i("iAP2 over bluetooth for wireless CarPlay.\n");
        if(CIpodVehicle::getbtSppConnStatus() == ipod_SppState_Connected){
            handle = 0xFF;
            m_connMode = ConnMode_BLUETOOTH;
            ret = 0;
        }else{
            CIpodLog::i("ipod over buletooth device open failed!\n");
            ret = -1;
        }
    }
    else if( CIpodConfig::getMode() == Mode_CARPLAY && CIpodConfig::connMode() == ConnMode_WiFi )
    {
        CIpodVehicle::setWiFiConnStatus(WIFI_CONNECTED);
        handle = 0xFE;
        m_connMode = ConnMode_WiFi;
        ret = 0;
        CIpodLog::i("iAP2 over Wi-Fi for wireless CarPlay.\n");
    }

    if (ret == 0) {
        m_Handle = handle;
    }
    return ret;
}

bool CIpodDevice::isIpodDevice(int handle) {
    struct hidraw_devinfo dinfo;
#ifdef __ANDROID__
    ioctl(handle, _IOR('H', 0x03, struct hidraw_devinfo), &dinfo);
#else
    ioctl(handle, HIDIOCGRAWINFO, &dinfo);
#endif
    return (dinfo.vendor == 0x05AC) ? true : false;
}

int CIpodDevice::checkIap2Support() {
    CIpodLog::i("[ SharkCarPlay ] checkIap2Support:  DETECT\n");

    if( CIpodConfig::getHidg() == 1)
    {
        m_ProtInitState = IPODProtInitState::SUCCEED;
        m_Iap2Support = true;
//        sem_wait(&m_ProtocolSem);
        return (m_ProtInitState == IPODProtInitState::SUCCEED) ? 0 : -1;

    }else{
        m_ProtInitState = IPODProtInitState::INITING;
    //    if (send(iAP2CheckBuf, sizeof(iAP2CheckBuf)) == -1) {
    //        CIpodLog::i("CIpodDevice::checkIap2Support, send error! %s\n", strerror(errno));
    //        return -1;
    //    }

        sem_wait(&m_ProtocolSem);
        return (m_ProtInitState == IPODProtInitState::SUCCEED) ? 0 : -1;
    }
}

int CIpodDevice::packetProc(const uint8 *data, uint16 len, bool native) {
    if (m_Protocol != NULL) {
        return m_Protocol->packetProc(data, len, native);
    }
    return -1;
}

void CIpodDevice::packetAdd(IpodPacket *packet) {
    pthread_mutex_lock(&m_PacketMutex);
    m_Packets.push_back(packet);
    pthread_mutex_unlock(&m_PacketMutex);
    sem_post(&m_PacketSem);
}

void CIpodDevice::debugHexBuf(const char *tag, const uint8 *data, uint16 len)
{
    uint16 debugLen = len;
     std::string buf;
    buf.append(tag);
    buf.append(" ---- ");
    for (uint16 i = 0; i < debugLen; i++) {
        char temp[10];
        sprintf(temp, "%02x ", data[i]);
        buf.append(temp);
    }
    buf.append("\n");
    CIpodLog::d("%s", buf.data());

//#ifdef __ANDROID__
//    std::string buf;
//
//    buf.append(tag);
//    buf.append("\n");
//    int j = 0;
//    for (uint16 i = 0; i < len; i++) {
//        char temp[10];
//        sprintf(temp, "%02x ", data[i]);
//        buf.append(temp);
//        j = j + 1;
//        if (j == 32) {
//            CIpodLog::d("%s \n", buf.data());
//            buf.clear();
//            j = 0;
//        }
//    }
//
//    CIpodLog::d("%s\n", buf.data());
//    CIpodLog::d("%d 个字节打印 完成 \n",  len + 1);
//    buf.clear();
//#else
//    CIpodLog::d("%s ---- ", tag);
//    for (uint16 i = 0; i < debugLen; i++) {
//        CIpodLog::d("%02x ", data[i]);
//    }
//    CIpodLog::d("\n");
//#endif
}

std::string CIpodDevice::debugHexBufString(const uint8 *data, uint16 len)
{
    uint16 debugLen = len;
     std::string buf;
    for (uint16 i = 0; i < debugLen; i++) {
        char temp[10];
        sprintf(temp, "%02X ", data[i]);
        buf.append(temp);
    }
    buf.append("\n");
//    CIpodLog::d("%s", buf.data());
    return buf;
}

void CIpodDevice::debugHexBuf1(const char *tag, const char *data , uint16 len)
{
    uint16 debugLen = (len > 32) ? 32 : len;

#ifdef __ANDROID__
    std::string buf;
    buf.append(tag);
    buf.append(" ---- ");
    for (uint16 i = 0; i < debugLen; i++) {
        char temp[10];
        sprintf(temp, "%02x ", data[i]);
        buf.append(temp);
    }
    buf.append("\n");
    CIpodLog::d("%s", buf.data());
#else
    CIpodLog::d("%s ---- ", tag);
    for (uint16 i = 0; i < debugLen; i++) {
        CIpodLog::d("%02x ", data[i]);
    }
    CIpodLog::d("\n");
#endif
}

void *CIpodDevice::procThread(void *arg) {
    CIpodDevice *device = (CIpodDevice *)arg;

    int handle = device->getHandle();

    CIpodLog::w("==================== ProcessThread Start fd: %d ====================\n", handle );
    while (1) {
        sem_wait(&device->m_PacketSem);

        if (device->m_Exiting) {
            CIpodLog::i("ProcessThread exiting because iAP2 Device has been exited.\n");
            break;
        }
        pthread_mutex_lock(&device->m_PacketMutex);
        if (device->m_Packets.empty()) {
            CIpodLog::i("CIpodDevice::procThread, m_Packets is empty! continue...\n");
            pthread_mutex_unlock(&device->m_PacketMutex);
            continue;
        }
        std::list<IpodPacket *>::iterator iter = device->m_Packets.begin();
        if (iter != device->m_Packets.end()) {
            IpodPacket *packet = *iter;
            if (packet == NULL || packet->exit || device->m_Exiting) {
                CIpodLog::i("packet->exit = %d, device->m_Exiting = %d\n", packet->exit, device->m_Exiting);
                device->m_Packets.erase(iter);
                if(NULL != packet){
                    delete packet;
                }
                pthread_mutex_unlock(&device->m_PacketMutex);
                break;
            }
            if(NULL != packet && packet->len > 0){
                device->packetProc(packet->data, packet->len, packet->native);
            }
            usleep(10);
//            CIpodLog::i("packet->exit = %d, device->m_Exiting = %d\n", packet->exit, device->m_Exiting);
            if( device->m_Exiting){
            	CIpodLog::i("packet->exit = %d, device->m_Exiting = %d\n", packet->exit, device->m_Exiting);
            	break;
            }else{
            	 device->m_Packets.erase(iter); //这一行crash
            }

            if(NULL != packet){
                delete packet;
            }
        }
        usleep(10);
        pthread_mutex_unlock(&device->m_PacketMutex);
    }
    device->m_ProcTid = 0;
    CIpodLog::w("==================== ProcessThread end fd: %d   ====================\n", handle );
    return NULL;
}

void *CIpodDevice:: recvThread(void *arg) {
    int ret = -1;
    fd_set fds;
    struct timeval timeout;
    timeout.tv_sec = IPOD_READ_TIMEOUT;
    timeout.tv_usec = 0;
    ipod_t fd = 0;
    uint8 hidReceiveBuf[IPOD_PACKET_MAX_LENGTH] = { 0 };
    IpodPacket packet;
    packet.native = false;
    CIpodDevice *device = (CIpodDevice *) arg;
    if (device != NULL) {
        fd = device->getHandle();
    } else{
        CIpodLog::i("CIpodDevice::recvThread, device is null !!!!!!!!!!!!!!!\n");
        device->m_RecvTid = 0;
        return NULL;
    }
    CIpodLog::i( "==================== ReceiveThread start fd: %d ====================\n", fd );
    while (1) {
        if (device->m_Exiting) {
            CIpodLog::w("ReceiveThread exiting because iAP2 Device has been exited.\n");
            break;
        }

#if 0
        timeout.tv_sec = IPOD_READ_TIMEOUT;
        FD_ZERO(&fds);
        FD_SET(fd, &fds);

        ret = select(fd + 1, &fds, NULL, NULL, &timeout);
        if (ret < 0)
        {
            CIpodLog::i("iAP2 ReceiveThread select error\n");
            break;
        }
        else if (ret == 0)
        {
            CIpodLog::i("iAP2 ReceiveThread select timeout(no message), continue select.\n");
        }
        else if(ret > 0 && FD_ISSET(fd, &fds))
#endif
        {
            // 给 errno 复位,防止是上一次操作的错误  接收数据
            errno = 0;
            if( CIpodConfig::getHidg() == 1)
            {
            	 ret = read(fd,(uint8 *) hidReceiveBuf, IPOD_PACKET_MAX_LENGTH);
            	 if( ret > 0)
            	 {
//                     CIpodLog::w("hidg-iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                     std::string details =device-> debugHexBufString(hidReceiveBuf, ret);
//                     CIpodLog::w("hidg-iAP2LinkPackets:: | Received  | accessory    | ACK  | %d | %d | %s\n",hidReceiveBuf[5], hidReceiveBuf[6], details.data());
            		 device->debugHexBuf("hidg-IAP2-USB-Recv", hidReceiveBuf, ret); //Tinker
            		 CIpodLog::i("hidg-IAP2-USB-Recv length = %d . \n ",ret);
            	 }

            }else{
                int actual=0;
                //modify for reverse carplay Tinker
                if( device == NULL && device->m_Exiting)
                {
                	break;
                }
                ret=CIpodEvent::read(device->getHandle(), (uint8 *) hidReceiveBuf,IPOD_PACKET_MAX_LENGTH,&actual);
                if( ret > 0)
                {
//                    CIpodLog::w("iAP2LinkPackets:: | Direction | Accessory    | Type | Seq | Ack | Details \n");
//                    std::string details =device-> debugHexBufString(hidReceiveBuf, ret);
//                    CIpodLog::w("iAP2LinkPackets:: | Received  | accessory    | ACK  | %d | %d | %s\n",hidReceiveBuf[5], hidReceiveBuf[6], details.data());
                	CIpodLog::w("[IAP2-libusb]-Recv %d bytes: \n",ret);
                	device->debugHexBuf("[IAP2-libusb]-Recv", hidReceiveBuf, ret); //Tinker
//                	CIpodLog::i("libusb-IAP2-USB-Recv length = %d . \n ",ret);
                }
            }
//            device->debugHexBuf("IAP2-USB-Recv", hidReceiveBuf, IPOD_PACKET_MAX_LENGTH); //Tinker
            if (ret < 0)
            {
                CIpodLog::e("iAP2 ReceiveThread read error. errno is %d, strerror is %s, ret = %d\n", errno, strerror(errno), ret );
                break;
            } else if (ret > 0) {
            	// 2第一包，1最后一包，3是连续包
                int receivedPacketLen = ret;
                int hidHeaderLen = 0;
                if (CIpodConfig::getMode() == Mode_MEDIA || CIpodConfig::getHidg() == 1) {
                	//读数据
                    hidHeaderLen = HID_HEADER_LENGTH;
                    //判读第一种，首先都有ff 5a
                    if ( hidReceiveBuf[2] == 0xFF && hidReceiveBuf[3] == 0x5A ) {
                    	uint16 payloadLen = receivedPacketLen - hidHeaderLen; //去掉了hid头的长度
                    	if (hidReceiveBuf[1] == 0x00 || hidReceiveBuf[1] == 0x01) {
                    		//最后一包数据
                        	if( packet.len == 0 ){
                                memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                                packet.len += (receivedPacketLen - hidHeaderLen);
                        	}else{
                        		//      00 01 02 03 04 05 06 07 08
                        		//00 01 02 03 04 05 06 07 08
                            	//12 00 ff 5a 01 00 40 93 6a 0a 5f    40 40 03 96 aa 01 03 90 00 00
                        		uint16 contentLen = IAP2_BIG_ENDIAN( hidReceiveBuf[4], hidReceiveBuf[5]);
                        		if( contentLen == payloadLen)
                        		{
                                	packet.data[5] = hidReceiveBuf[7];
                                	packet.data[6] = hidReceiveBuf[8];
                        			//最后一包数据
                        			contentLen -= 10; //需要将payloadchecksum去掉
                        			uint8* content = (uint8*)malloc(contentLen);
                        			memset(content,0,contentLen);
                        			memcpy(content, hidReceiveBuf + hidHeaderLen + 9,contentLen);
                        			//连续包数据
                                    memcpy(packet.data + packet.len, content, contentLen);
                                    packet.len += contentLen;
                                    free(content);
                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,contentLen);
                        		}else{
                        			contentLen = payloadLen; //需要将payloadchecksum去掉
                        			uint8* content = (uint8*)malloc(contentLen);
                        			memset(content,0,contentLen);
                        			memcpy(content, hidReceiveBuf + hidHeaderLen,contentLen);
                        			//连续包数据
                                    memcpy(packet.data + packet.len, content, contentLen);
                                    packet.len += contentLen;
                                    free(content);
                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,contentLen);
                        		}
                        	}
                    	} else {
                    		// 2  或者 3
//                    		uint16 payloadLen = receivedPacketLen - hidHeaderLen; //去掉了hid头的长度
                    		//      00 01 02 03 04 05 06 07 08
                    		//00 01 02 03 04 05 06 07 08
                        	//12 00 ff 5a 01 00 40 93 6a 0a 5f    40 40 03 96 aa 01 03 90 00 00
                    		if(packet.len == 0)
                    		{
                    			uint16 contentLen = IAP2_BIG_ENDIAN( hidReceiveBuf[4], hidReceiveBuf[5]);
                    			//兼容另一种方式sync3
                    			if( contentLen == payloadLen )
                    			{
                        			contentLen -= 1; //需要将payloadchecksum去掉
                        			uint8* content = (uint8*)malloc(contentLen);
                        			memset(content,0,contentLen);
                        			memcpy(content, hidReceiveBuf + hidHeaderLen,contentLen);
                        			//第一包数据
                                    memcpy(packet.data + packet.len, content, contentLen);
                                    packet.len += contentLen;

                                    free(content);

                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,contentLen);
                    			}else{
                        			contentLen = payloadLen; //需要将payloadchecksum去掉
                        			uint8* content = (uint8*)malloc(contentLen);
                        			memset(content,0,contentLen);
                        			memcpy(content, hidReceiveBuf + hidHeaderLen,contentLen);
                        			//连续包数据
                                    memcpy(packet.data + packet.len, content, contentLen);
                                    packet.len += contentLen;
                                    free(content);
                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,contentLen);
                    			}
                    		}else{
                    			//连续包
                    			uint16 contentLen = IAP2_BIG_ENDIAN( hidReceiveBuf[4], hidReceiveBuf[5]);
                    			if( contentLen == payloadLen )
                    			{
                        			contentLen -= 10; //需要将payloadchecksum去掉
                        			uint8* content = (uint8*)malloc(contentLen);
                        			memset(content,0,contentLen);
                        			memcpy(content, hidReceiveBuf + hidHeaderLen + 9,contentLen);
                        			//连续包数据
                                    memcpy(packet.data + packet.len, content, contentLen);
                                    packet.len += contentLen;
                                    free(content);
                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,contentLen);
                    			}else{
                        			contentLen = payloadLen; //需要将payloadchecksum去掉
                        			uint8* content = (uint8*)malloc(contentLen);
                        			memset(content,0,contentLen);
                        			memcpy(content, hidReceiveBuf + hidHeaderLen,contentLen);
                        			//连续包数据
                                    memcpy(packet.data + packet.len, content, contentLen);
                                    packet.len += contentLen;
                                    free(content);
                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,contentLen);
                    			}

                    		}
                    		continue;

                    	}
                    } else {
                        if (hidReceiveBuf[1] == 0x00 || hidReceiveBuf[1] == 0x01) {
                            memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                            packet.len += (receivedPacketLen - hidHeaderLen);

                            CIpodLog::e("iAP2 combine partial bufs end = %d ,new =%d \n",packet.len ,(receivedPacketLen - hidHeaderLen));
                        }
                        else {
                            memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                            packet.len += (receivedPacketLen - hidHeaderLen);
                            CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,(receivedPacketLen - hidHeaderLen));
                            continue;
                        }
                    }
                } else if (CIpodConfig::getMode() == Mode_CARLIFE
                        || CIpodConfig::getMode() == Mode_CARPLAY) {
//                    hidHeaderLen = 0;
//                    memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
//                    packet.len += (receivedPacketLen - hidHeaderLen);
                	// 添加无线CarPlay连接的蓝牙数据组包
                	// iAP2CheckBufHongQi
                	if(memcmp(iAP2CheckBuf, hidReceiveBuf, sizeof(iAP2CheckBuf)) == 0
                			|| memcmp(iAP2CheckBufHongQi, hidReceiveBuf, sizeof(iAP2CheckBufHongQi)) == 0 )
                	{
                		//detect data
                		hidHeaderLen = 0;
                		memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                		packet.len += (receivedPacketLen - hidHeaderLen);
                	}else{
                    	hidHeaderLen = 0;
                    	uint16 rawlength = IAP2_BIG_ENDIAN( hidReceiveBuf[2], hidReceiveBuf[3] );
                    	//特殊处理一下sync3 2.2 系统
                    	if(rawlength == 928 && receivedPacketLen == 9)
                    	{
                    		hidReceiveBuf[2] = 0x00;
                    		hidReceiveBuf[3] = 0x09;
                    		rawlength = 9;
                    	}
                    	if ( hidReceiveBuf[0] == 0xFF && hidReceiveBuf[1] == 0x5A && receivedPacketLen != rawlength) {
                    		//两种情况，1. 一是数据包不足
                    		//2.二是数据包发生了粘包现象
                    		//需要走组包机制
                    		if(receivedPacketLen > rawlength)
                    		{
                    			//粘包处理
                    			//int receivedPacketLen = ret;
                    			//hidHeaderLen hid信息头，两个字节
                    			//device->packetAdd(new IpodPacket(packet));

                    			for(int i = 0; i < receivedPacketLen; )
                    			{
                    				if(hidReceiveBuf[i] == 0xFF && hidReceiveBuf[(i+1)] == 0x5A)
                    				{
                    					uint16 singlePackLen = IAP2_BIG_ENDIAN( hidReceiveBuf[(i+2)], hidReceiveBuf[(i+3)] );
                    					uint8 singleBuf [singlePackLen];
                    					memset(singleBuf, 0, singlePackLen);
                    					memcpy(singleBuf, hidReceiveBuf + i, singlePackLen);
                    					i += singlePackLen;
                    					//post data
                    					 CIpodLog::e("iAP2 split partial bufs = %d \n",singlePackLen);
                    					IpodPacket tempPacket;
                    					memcpy(tempPacket.data + tempPacket.len, singleBuf, singlePackLen);
                    					tempPacket.len += singlePackLen;
                    					device->packetAdd(new IpodPacket(tempPacket));
                    				}
                    			}
                    			packet.ignore = true;
                    		}else{
                        		if(packet.len == 0)
                        		{
                        			packet.total = rawlength;
                        			memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                        			packet.len += (receivedPacketLen - hidHeaderLen);
                                    CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,receivedPacketLen);
                        		}
                        		continue;
                    		}
                    	}
                    	else if ( hidReceiveBuf[0] == 0xFF && hidReceiveBuf[1] == 0x5A && receivedPacketLen == rawlength){
                    		//正常数据包
//                    		memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
//                    		packet.len += (receivedPacketLen - hidHeaderLen);
                    		//正常数据包
                    		hidHeaderLen = 0;
                    		memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                    		packet.len += (receivedPacketLen - hidHeaderLen);
                    		device->packetAdd(new IpodPacket(packet));
                    		packet.ignore = true;
                    	}else{
                    		//非FF 5A开头的是连续数据包
                    		memcpy(packet.data + packet.len, hidReceiveBuf + hidHeaderLen, receivedPacketLen - hidHeaderLen);
                    		packet.len += (receivedPacketLen - hidHeaderLen);
                    		CIpodLog::e("iAP2 combine partial bufs = %d ,new =%d \n",packet.len ,receivedPacketLen);
                    		if(packet.len != packet.total){
                    			continue;
                    		}
                    	}

                	}
                }

                if (device->m_ProtInitState == IPODProtInitState::INITING ||
                		memcmp(iAP2CheckBuf, packet.data, sizeof(iAP2CheckBuf)) == 0
						|| memcmp(iAP2CheckBufHongQi, packet.data, sizeof(iAP2CheckBufHongQi)) == 0 ) {
                    if (memcmp(iAP2CheckBuf, packet.data, sizeof(iAP2CheckBuf)) == 0
                    		|| memcmp(iAP2CheckBufHongQi, packet.data, sizeof(iAP2CheckBufHongQi)) == 0 ) {
                        CIpodLog::i("[  Device   ] step 2:  DETECT over USB.\n");
                        device->m_ProtInitState = IPODProtInitState::SUCCEED;
                        device->m_Iap2Support = true;
                        sem_post(&device->m_ProtocolSem);
                        //需要回复一条给车机 Tinker
                        if (device->send(iAP2CheckBuf, sizeof(iAP2CheckBuf)) == -1) {
                            CIpodLog::i("CIpodDevice::responseIap2Support, send error! %s\n", strerror(errno));
                        }else{
                        	CIpodLog::i("CIpodDevice::responseIap2Support, send success!\n");
                        }
                    } else if (memcmp(iAP1ReqIdentifyBuf, packet.data, sizeof(iAP1ReqIdentifyBuf)) == 0
                            || memcmp(iAP1AckBuf, packet.data, sizeof(iAP1AckBuf)) == 0) {
                        CIpodLog::i("CIpodDevice::recvThread, support iap1!\n");
                        device->m_ProtInitState = IPODProtInitState::SUCCEED;
                        device->m_Iap2Support = false;
                        sem_post(&device->m_ProtocolSem);
                    }
                } else {
                	if( !packet.ignore)
                	{
                		device->packetAdd(new IpodPacket(packet));
                	}

                }
                packet.clear();
            }
        }
    }
    if (device->m_ProtInitState == IPODProtInitState::INITING) {
        device->m_ProtInitState = IPODProtInitState::FAILED;
        sem_post(&device->m_ProtocolSem);
    }
    device->m_DeviceExist = false;
    device->m_RecvTid = 0;
    CIpodEvent::sendEvent(IPOD_EVT_CONNECT_STATUS_CHANGED, fd, 0);
    CIpodLog::w( "==================== ReceiveThread end fd: %d   ====================\n", fd );
    return NULL;
}

void *CIpodDevice::nativeThread(void *arg) {
    int ret = -1;
    fd_set fds;
    struct timeval timeout;
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    int nativefd = 0;

    CIpodDevice *device = (CIpodDevice *) arg;
    nativefd = CIpodNative::getHandle();
    CIpodLog::i("CIpodDevice::nativeThrad, start ~~~~~~~~~~~~~~~~~~~~~~~~~ nativefd = %d\n", nativefd);
    while (1) {
        if (device->m_Exiting) {
            CIpodLog::i("CIpodDevice::nativeThread, ipod is destroyed, exiting...!\n");
            break;
        }

        timeout.tv_sec = 5;
        FD_ZERO(&fds);
        FD_SET(nativefd, &fds);
        ret = select(nativefd + 1, &fds, NULL, NULL, &timeout);
        if (ret < 0) {
            CIpodLog::e("CIpodDevice::nativeThrad, select error!!!!!!!!!!!!!!!\n");
            break;
        } else if (ret == 0) {
            CIpodLog::i("CIpodDevice::nativeThrad, select timeout(no message)--continue select!!!!!!!!!\n");
        } else if (ret > 0 && FD_ISSET(nativefd, &fds)) {
            IpodPacket *packet = new IpodPacket();
            ret = read(nativefd, (uint8 *) packet->data, 4096);
            if (ret < 0) {
                CIpodLog::i("CIpodDevice::nativeThrad, read return(%d)--%s!!!!!!!!!\n", errno, strerror(errno));
                if(NULL != packet){
                    delete packet;
                }
                break;
            } else if (ret > 0) {
                packet->len = ret;
                packet->native = true;
                device->packetAdd(packet);
            }
        }
    }
    device->m_NativeTid = 0;
    CIpodLog::i("CIpodDevice::nativeThrad, exit success!!!!\n");
    return 0;
}
